//! DSA - Digital Signature Algorithm 是Schnorr和Elgamal签名算法的变种，被美国NIST作为DSS（Digital Signature Standard）。
//! 简单的说，这是一种更高级的验证方式，用作数字签名，不单单只有公钥、私钥，还有数字签名。私钥加密生成数字签名，公钥验证数据及签名。
//! 如果数据和签名不匹配则认为验证失败。
//!

use crate::error::{Error, ErrorKind};
use base64::Engine;
use crypto::{
    digest::Digest,
    sha3::{Sha3, Sha3Mode},
};
use dsa::{
    pkcs8::{der::Decode, DecodePrivateKey, DecodePublicKey, EncodePrivateKey, EncodePublicKey},
    signature::{SignatureEncoding, SignerMut, Verifier},
    Components, KeySize, Signature, SigningKey, VerifyingKey,
};
use rand::SeedableRng;

pub const DEFAULT_SEED: &'static str = "$%^*%^()(HJG8awfjas7";

pub fn private_key_str(private_key: &SigningKey) -> Result<String, Error> {
    let doc = private_key
        .to_pkcs8_der()
        .map_err(|_| Error::from_kind(ErrorKind::Msg("pkcs8 error!".to_string())))?;
    let bytes = doc.as_bytes();
    Ok(base64::engine::general_purpose::STANDARD.encode(bytes))
}

pub fn public_key_str(public_key: &VerifyingKey) -> Result<String, Error> {
    let doc = public_key
        .to_public_key_der()
        .map_err(|_| Error::from_kind(ErrorKind::Msg("pkcs8 error!".to_string())))?;
    let bytes = doc.as_bytes();
    Ok(base64::engine::general_purpose::STANDARD.encode(bytes))
}

pub fn from_bytes_to_private(private_key: &str) -> Result<SigningKey, Error> {
    let bytes = base64::engine::general_purpose::STANDARD.decode(private_key)?;
    Ok(SigningKey::from_pkcs8_der(&bytes)
        .map_err(|_| Error::from_kind(ErrorKind::Msg("from pkcs8 der error".to_string())))?)
}

pub fn from_bytes_to_public(public_key: &str) -> Result<VerifyingKey, Error> {
    let bytes = base64::engine::general_purpose::STANDARD.decode(public_key)?;
    Ok(VerifyingKey::from_public_key_der(&bytes)
        .map_err(|_| Error::from_kind(ErrorKind::Msg("from public key der error".to_string())))?)
}

/// 用私钥进行数字签名
/// data: 要签名的数据
/// private_key: Base64加密的私钥
pub fn sign(data: &[u8], private_key: &str) -> Result<String, Error> {
    let mut private = from_bytes_to_private(private_key)?;
    let sig = private.sign(data);
    let bytes = sig.to_vec();
    Ok(base64::engine::general_purpose::STANDARD.encode(&bytes))
}

/// 用公钥进行验签
/// data: 要签名的数据
/// public_key: Base64加密的私钥
/// sign: base64加密后的字符串
pub fn verify(data: &[u8], public_key: &str, sign: &str) -> Result<(), Error> {
    let public_key_bytes = base64::engine::general_purpose::STANDARD.decode(public_key)?;
    let sign_bytes = base64::engine::general_purpose::STANDARD.decode(sign)?;
    let public_key = VerifyingKey::from_public_key_der(&public_key_bytes)
        .map_err(|_| Error::from_kind(ErrorKind::Msg("from public key der error".to_string())))?;
    let signature = Signature::from_der(&sign_bytes)
        .map_err(|_| Error::from_kind(ErrorKind::Msg("signature from der error".to_string())))?;
    Ok(public_key
        .verify(data, &signature)
        .map_err(|_| Error::from_kind(ErrorKind::Msg("verify failed".to_string())))?)
}

/// 生成秘钥
/// seed:种子
/// 返回密钥对
pub fn init_key(seed: &str) -> (SigningKey, VerifyingKey) {
    let mut sha3 = Sha3::new(Sha3Mode::Keccak256);
    sha3.input_str(seed);
    let mut bytes = [0u8; 32];
    sha3.result(&mut bytes);
    let mut rng = rand::rngs::StdRng::from_seed(bytes);
    let components = Components::generate(&mut rng, KeySize::DSA_2048_256);
    let signing_key = SigningKey::generate(&mut rng, components);
    let verifying_key = signing_key.verifying_key().clone();
    (signing_key, verifying_key)
}
/// 生成默认的
pub fn init_key_default() -> (SigningKey, VerifyingKey) {
    init_key(DEFAULT_SEED)
}
